<?php
/**
 * Lớp hỗ trợ xử lý Attribute trong PHP
 * @author Mr.UBKey
 * @package XPHP
 */
class XPHP_Attribute
{
	/**
	 * Lưu trữ các attribute
	 * @var array
	 */
	public $attributes = null;
	
	/**
	 * Hàm khởi tạo
	 * @param array $attributes Mảng các attribute
	 */
	protected function __construct($attributes)
	{
		$this->attributes = $attributes;
		
		if (!$attributes)
			return;
		
		foreach($attributes as $key => $item)
			if (is_array($item))
				$this->attributes[$key] = new XPHP_Attribute($item);
	}
	
	/**
	 * Lấy ra giá trị của attribute
	 * @param string $prop_name Tên attribute cần lấy giá trị
	 * @return array Mảng chứa các giá trị
	 */
   	public function __get($prop_name)
   	{
       if (isset($this->attributes[$prop_name]))
           return $this->attributes[$prop_name];
   	}

   	/**
   	 * Phân tích để lấy ra chuỗi chứa thông tin của attribute (Attribute Lines)
   	 * @param string $doc_comment Phần Doc được lấy từ Reflection Object thông qua getDocComment()
   	 * @return string Kết quả phân tích Attribute Lines.
   	 */
	private static function ParseDocComments($doc_comment)
	{
		$comments = explode("\n",$doc_comment);
		
		$yaml = '';
		$within = false;
		
		foreach($comments as $comment)
		{
			$line = substr(trim($comment),2);
			if (strpos($line,'[[') === 0)
				$within = true;
			else if ($within)
			{
				if (strpos($line,']]') === 0)
					break;
				else
					$yaml .= $line . "\n";
			}
		}
		
		return $yaml;
	}
	
	/**
	 * Lấy ra Attributes của phương thức
	 * @param mixed $class Thể hiện của lớp hoặc tên lớp
	 * @param string $method Tên phương thức
	 * @return XPHP_Attribute Trả về thể hiện của XPHP_Attribute
	 */
	
	public static function MethodAttributes($class, $method)
	{
		$method = new ReflectionMethod($class, $method);
		$attrl = self::ParseDocComments($method->getDocComment());
		
		return new XPHP_Attribute(self::parseAttributeLines($attrl));
	}
	
	/**
	 * Lấy ra Attributes của lớp
	 * @param mixed $class Thể hiện của một lớp hoặc tên lớp
	 * @return XPHP_Attribute Trả về thể hiện của XPHP_Attribute
	 */
	public static function ClassAttributes($class)
	{
		$class = new ReflectionClass($class);
		$attrl = self::ParseDocComments($class->getDocComment());
		
		return new XPHP_Attribute(self::parseAttributeLines($attrl));
	}
	
	/**
	 * Lấy ra Attributes của thuộc tính
	 * @param mixed $class Thể hiện của một lớp hoặc tên lớp
	 * @param string $prop Tên thuộc tính
	 * @return XPHP_Attribute Trả về thể hiện của XPHP_Attribute
	 */
	
	public static function PropertyAttributes($class, $prop)
	{
		$prop = new ReflectionProperty($class, $prop);
		$attrl = self::ParseDocComments($prop->getDocComment());
		
		return new XPHP_Attribute(self::parseAttributeLines($attrl));
	}
	
	/**
	 * Phân tích Attribute Lines để lấy ra mảng các thuộc tính và giá trị của nó
	 * @param AttributeLines $attrl
	 */
	private static function parseAttributeLines($attrl)
	{	
		//Cắt bỏ dấu ngắt dòng cuối cùng
		$attrl = rtrim($attrl, "\n");
		//Cắt thành các mảng
		$lines = explode("\n", $attrl);
		
		//Phân tách dòng thành các attribute và giá trị của nó
		$arrAttribues = array();
		foreach ($lines as $line)
		{
			$arr = explode(":", $line);
			if(sizeof($arr) == 2)
				$arrAttribues[$arr[0]] = trim($arr[1]);
		}
		
		//Xử lý để phân cấp thuộc tính
		$attribues = array();
		$flag = "";
		foreach ($arrAttribues as $attr => $value)
		{
			//Nếu có khoảng trắng phía trước tên thuộc tính đó là thuộc tính con
			if(strlen($attr) > strlen(ltrim($attr)))
			{
				$attribues[$flag][trim($attr)] = $value;
				continue;
			}
			//Nếu không phải là thuộc tính con
			if($value == "")
			{
				//Nếu là thuộc tính cha
				$flag = $attr;
				$attribues[$attr] = $value;
			}
			else 
				$attribues[$attr] = $value;
		}
		
		return $attribues;
	}
	
}